﻿using Koala.Pro.Common;
using Koala.Pro.Core;
using Koala.Pro.Core.Dto;
using Koala.Pro.Core.Models;
using Koala.Pro.Helpers;
using Koala.Pro.Models;
using SqlSugar;

namespace Koala.Pro.Services
{
    public class UserService : MyCrudService<UserInfo, int, UserPagedDto>, IUserService, IMyCrudService<UserInfo, int, UserPagedDto>, ITransientDependency, IDependency
    {
        private IBlackIPService _blackIPService;

        private ILoginLogService _loginLogService;

        public UserService(IBlackIPService blackIPService, ILoginLogService loginLogService)
        {
            _blackIPService = blackIPService;
            _loginLogService = loginLogService;
        }

        public override Task<Dictionary<string, string>> GetColumnNameAlias()
        {
            return Task.FromResult(new Dictionary<string, string>
        {
            { "PID", "父ID" },
            { "HandNo", "用户编码" },
            { "Name", "用户名/登录名" },
            { "Password", "用户密码" },
            { "FullName", "姓名" },
            { "Nickname", "用户呢称" },
            { "IsExpire", "是否过期" },
            { "ExpireDate", "过期时间" },
            { "Title", "职务头衔" },
            { "IdentityCard", "身份证号码" },
            { "MobilePhone", "移动电话" },
            { "OfficePhone", "办公电话" },
            { "HomePhone", "家庭电话" },
            { "Email", "邮件地址" },
            { "Address", "住址" },
            { "WorkAddr", "办公地址" },
            { "Gender", "性别" },
            { "Birthday", "出生日期" },
            { "QQ", "QQ号码" },
            { "Signature", "个性签名" },
            { "AuditStatus", "审核状态" },
            { "AvatarUrl", "头像" },
            { "Note", "备注" },
            { "CustomField", "自定义字段" },
            { "Dept_ID", "默认部门ID" },
            { "DeptName", "默认部门名称" },
            { "Company_ID", "所属公司ID" },
            { "CompanyName", "所属公司名称" },
            { "SortCode", "排序码" },
            { "Creator", "创建人" },
            { "Creator_ID", "创建人ID" },
            { "CreateTime", "创建时间" },
            { "Editor", "编辑人" },
            { "Editor_ID", "编辑人ID" },
            { "EditTime", "编辑时间" },
            { "Deleted", "是否已删除" },
            { "Question", "密保：提示问题" },
            { "Answer", "密保:问题答案" },
            { "LastLoginIP", "上次登录IP" },
            { "LastLoginTime", "上次登录时间" },
            { "LastMacAddress", "上次Mac地址" },
            { "CurrentLoginIP", "当前登录IP" },
            { "CurrentLoginTime", "当前登录时间" },
            { "CurrentMacAddress", "当前Mac地址" },
            { "LastPasswordTime", "最后修改密码日期" },
            { "OpenId", "微信用户OpenID" },
            { "UnionId", "微信多平台应用下的统一ID" },
            { "Status", "微信关注状态" },
            { "SubscribeWechat", "公众号" },
            { "DeptPermission", "科室权限" },
            { "CorpUserId", "企业微信UserID" },
            { "CorpStatus", "企业微信状态" }
        });
        }

        protected override ISugarQueryable<UserInfo> CreateFilteredQueryAsync(UserPagedDto input)
        {
            ISugarQueryable<UserInfo> sugarQueryable = base.CreateFilteredQueryAsync(input);
            if (!input.Role_ID.IsNullOrEmpty())
            {
                return (from t in base.Client.Queryable((UserInfo t, User_RoleInfo m) => t.Id == m.User_ID && m.Role_ID.ToString() == input.Role_ID).WhereIF(!input.HandNo.IsNullOrWhiteSpace(), (UserInfo t) => t.HandNo.Contains(input.HandNo)).WhereIF(!input.Name.IsNullOrWhiteSpace(), (UserInfo t) => t.Name.Contains(input.Name))
                        .WhereIF(!input.FullName.IsNullOrWhiteSpace(), (UserInfo t) => t.FullName.Contains(input.FullName))
                        select (t) into t
                        select (t)).MergeTable();
            }

            if (input.AgeStart.HasValue)
            {
                var year = DateTime.Now.Year - input.AgeStart.Value;
                input.BirthdayStart = new DateTime(year, 1, 1);
            }
            if (input.AgeEnd.HasValue)
            {
                var year = DateTime.Now.Year - input.AgeEnd.Value;
                input.BirthdayEnd = new DateTime(year, 1, 1);
            }

            return sugarQueryable.WhereIF(input.ID.HasValue, (UserInfo t) => t.Id.Equals(input.ID)).WhereIF(input.ExcludeId.HasValue, (UserInfo t) => (int?)t.Id != input.ExcludeId).WhereIF(input.PID.HasValue, (UserInfo s) => s.PID == input.PID)
                .WhereIF(!input.HandNo.IsNullOrWhiteSpace(), (UserInfo t) => t.HandNo.Contains(input.HandNo))
                .WhereIF(!input.Name.IsNullOrWhiteSpace(), (UserInfo t) => t.Name.Contains(input.Name))
                .WhereIF(!input.FullName.IsNullOrWhiteSpace(), (UserInfo t) => t.FullName.Contains(input.FullName))
                .WhereIF(!input.Nickname.IsNullOrWhiteSpace(), (UserInfo t) => t.Nickname.Contains(input.Nickname))
                .WhereIF(input.IsExpire.HasValue, (UserInfo t) => (bool?)t.IsExpire == input.IsExpire)
                .WhereIF(input.ExpireDateStart.HasValue, (UserInfo s) => s.ExpireDate >= input.ExpireDateStart.Value)
                .WhereIF(input.ExpireDateEnd.HasValue, (UserInfo s) => s.ExpireDate <= input.ExpireDateEnd.Value)
                .WhereIF(!input.Title.IsNullOrWhiteSpace(), (UserInfo t) => t.Title.Contains(input.Title))
                .WhereIF(!input.IdentityCard.IsNullOrWhiteSpace(), (UserInfo t) => t.IdentityCard.Contains(input.IdentityCard))
                .WhereIF(!input.MobilePhone.IsNullOrWhiteSpace(), (UserInfo t) => t.MobilePhone.Contains(input.MobilePhone))
                .WhereIF(!input.OfficePhone.IsNullOrWhiteSpace(), (UserInfo t) => t.OfficePhone.Contains(input.OfficePhone))
                .WhereIF(!input.HomePhone.IsNullOrWhiteSpace(), (UserInfo t) => t.HomePhone.Contains(input.HomePhone))
                .WhereIF(!input.Email.IsNullOrWhiteSpace(), (UserInfo t) => t.Email.Contains(input.Email))
                .WhereIF(!input.Address.IsNullOrWhiteSpace(), (UserInfo t) => t.Address.Contains(input.Address))
                .WhereIF(!input.WorkAddr.IsNullOrWhiteSpace(), (UserInfo t) => t.WorkAddr.Contains(input.WorkAddr))
                .WhereIF(!input.Gender.IsNullOrWhiteSpace(), (UserInfo t) => t.Gender.Contains(input.Gender))
                .WhereIF(input.BirthdayStart.HasValue, (UserInfo s) => s.Birthday <= input.BirthdayStart.Value)
                .WhereIF(input.BirthdayEnd.HasValue, (UserInfo s) => s.Birthday >= input.BirthdayEnd.Value)
                .WhereIF(!input.QQ.IsNullOrWhiteSpace(), (UserInfo t) => t.QQ.Contains(input.QQ))
                .WhereIF(!input.Signature.IsNullOrWhiteSpace(), (UserInfo t) => t.Signature.Contains(input.Signature))
                .WhereIF(!input.AuditStatus.IsNullOrWhiteSpace(), (UserInfo t) => t.AuditStatus.Contains(input.AuditStatus))
                .WhereIF(!input.Note.IsNullOrWhiteSpace(), (UserInfo t) => t.Note.Contains(input.Note))
                .WhereIF(!input.CustomField.IsNullOrWhiteSpace(), (UserInfo t) => t.CustomField.Contains(input.CustomField))
                .WhereIF(!input.Dept_ID.IsNullOrWhiteSpace(), (UserInfo t) => t.Dept_ID.Equals(input.Dept_ID))
                .WhereIF(!input.DeptName.IsNullOrWhiteSpace(), (UserInfo t) => t.DeptName.Contains(input.DeptName))
                .WhereIF(!input.Company_ID.IsNullOrWhiteSpace(), (UserInfo t) => t.Company_ID.Equals(input.Company_ID))
                .WhereIF(!input.CompanyName.IsNullOrWhiteSpace(), (UserInfo t) => t.CompanyName.Contains(input.CompanyName))
                .WhereIF(!input.SortCode.IsNullOrWhiteSpace(), (UserInfo t) => t.SortCode.Contains(input.SortCode))
                .WhereIF(!input.Creator.IsNullOrWhiteSpace(), (UserInfo t) => t.Creator.Contains(input.Creator))
                .WhereIF(!input.Creator_ID.IsNullOrWhiteSpace(), (UserInfo t) => t.Creator_ID.Contains(input.Creator_ID))
                .WhereIF(input.CreateTimeStart.HasValue, (UserInfo s) => s.CreateTime >= input.CreateTimeStart.Value)
                .WhereIF(input.CreateTimeEnd.HasValue, (UserInfo s) => s.CreateTime <= input.CreateTimeEnd.Value)
                .WhereIF(!input.Editor.IsNullOrWhiteSpace(), (UserInfo t) => t.Editor.Contains(input.Editor))
                .WhereIF(!input.Editor_ID.IsNullOrWhiteSpace(), (UserInfo t) => t.Editor_ID.Contains(input.Editor_ID))
                .WhereIF(input.EditTimeStart.HasValue, (UserInfo s) => s.EditTime >= input.EditTimeStart.Value)
                .WhereIF(input.EditTimeEnd.HasValue, (UserInfo s) => s.EditTime <= input.EditTimeEnd.Value)
                .WhereIF(input.Deleted.HasValue, (UserInfo s) => s.Deleted == (int?)input.Deleted.Value)
                .WhereIF(!input.Question.IsNullOrWhiteSpace(), (UserInfo t) => t.Question.Contains(input.Question))
                .WhereIF(!input.Answer.IsNullOrWhiteSpace(), (UserInfo t) => t.Answer.Contains(input.Answer))
                .WhereIF(!input.LastLoginIP.IsNullOrWhiteSpace(), (UserInfo t) => t.LastLoginIP.Contains(input.LastLoginIP))
                .WhereIF(input.LastLoginTimeStart.HasValue, (UserInfo s) => s.LastLoginTime >= input.LastLoginTimeStart.Value)
                .WhereIF(input.LastLoginTimeEnd.HasValue, (UserInfo s) => s.LastLoginTime <= input.LastLoginTimeEnd.Value)
                .WhereIF(!input.LastMacAddress.IsNullOrWhiteSpace(), (UserInfo t) => t.LastMacAddress.Contains(input.LastMacAddress))
                .WhereIF(!input.CurrentLoginIP.IsNullOrWhiteSpace(), (UserInfo t) => t.CurrentLoginIP.Contains(input.CurrentLoginIP))
                .WhereIF(input.CurrentLoginTimeStart.HasValue, (UserInfo s) => s.CurrentLoginTime >= input.CurrentLoginTimeStart.Value)
                .WhereIF(input.CurrentLoginTimeEnd.HasValue, (UserInfo s) => s.CurrentLoginTime <= input.CurrentLoginTimeEnd.Value)
                .WhereIF(!input.CurrentMacAddress.IsNullOrWhiteSpace(), (UserInfo t) => t.CurrentMacAddress.Contains(input.CurrentMacAddress))
                .WhereIF(input.LastPasswordTimeStart.HasValue, (UserInfo s) => s.LastPasswordTime >= input.LastPasswordTimeStart.Value)
                .WhereIF(input.LastPasswordTimeEnd.HasValue, (UserInfo s) => s.LastPasswordTime <= input.LastPasswordTimeEnd.Value)
                .WhereIF(!input.OpenId.IsNullOrWhiteSpace(), (UserInfo t) => t.OpenId.Contains(input.OpenId))
                .WhereIF(!input.UnionId.IsNullOrWhiteSpace(), (UserInfo t) => t.UnionId.Contains(input.UnionId))
                .WhereIF(!input.Status.IsNullOrWhiteSpace(), (UserInfo s) => s.Status == input.Status)
                .WhereIF(!input.SubscribeWechat.IsNullOrWhiteSpace(), (UserInfo t) => t.SubscribeWechat.Contains(input.SubscribeWechat))
                .WhereIF(!input.DeptPermission.IsNullOrWhiteSpace(), (UserInfo t) => t.DeptPermission.Contains(input.DeptPermission))
                .WhereIF(!input.CorpUserId.IsNullOrWhiteSpace(), (UserInfo t) => t.CorpUserId.Contains(input.CorpUserId))
                .WhereIF(!input.CorpStatus.IsNullOrWhiteSpace(), (UserInfo t) => t.CorpStatus.Contains(input.CorpStatus));
        }

        protected override ISugarQueryable<UserInfo> CreateFilteredQueryAsync(string filter)
        {
            return base.CreateFilteredQueryAsync(filter).WhereIF(!filter.IsNullOrWhiteSpace(), (UserInfo t) => t.HandNo.Contains(filter) || t.Name.Contains(filter) || t.FullName.Contains(filter) || t.Nickname.Contains(filter) || t.Title.Contains(filter) || t.IdentityCard.Contains(filter) || t.Email.Contains(filter) || t.Address.Contains(filter) || t.WorkAddr.Contains(filter) || t.Gender.Equals(filter) || t.QQ.Equals(filter) || t.Signature.Contains(filter) || t.Note.Contains(filter) || t.CustomField.Contains(filter) || t.DeptName.Contains(filter) || t.CompanyName.Contains(filter));
        }

        protected override ISugarQueryable<UserInfo> ApplyDefaultSorting(ISugarQueryable<UserInfo> query)
        {
            return query.OrderBy((UserInfo t) => t.CreateTime, OrderByType.Desc);
        }

        public async Task<LoginResult> Login(LoginDto dto)
        {
            LoginResult result = new LoginResult();
            UserInfo userInfo = await GetFirstAsync((UserInfo s) => s.Name == dto.Username);
            if (userInfo != null && !userInfo.IsExpire && userInfo.Deleted <= 0)
            {
                DateTime? expireDate = userInfo.ExpireDate;
                if (expireDate.HasValue && expireDate.Value < DateTime.Now)
                {
                    result.ErrorMessage = "用户身份已过期";
                    if (userInfo.Name != "admin")
                    {
                        userInfo.IsExpire = true;
                        await UpdateAsync(userInfo);
                    }
                }
                else if (_blackIPService.ValidateIPAccess(dto.Ip, userInfo.Id))
                {
                    var pwdHash = EncryptHelper.ComputeHash(dto.Password, userInfo.Name.ToLower());
                    if (pwdHash != userInfo.Password)
                    {
                        result.ErrorMessage = "账号或者密码错误";
                    }
                    else
                    {
                        string note = $"用户 {userInfo.FullName}【{userInfo.Name}】登录成功。";
                        await _loginLogService.AddLoginLog(userInfo, dto.SystemType, note, dto.Ip, dto.MacAddr);
                        result.UserInfo = userInfo;
                        result.Success = true;
                    }
                }
                else
                {
                    result.ErrorMessage = "用户登录操作被黑白名单禁止登录";
                    await _loginLogService.AddLoginLog(userInfo, dto.SystemType, result.ErrorMessage, dto.Ip, dto.MacAddr);
                }
            }
            else
            {
                result.ErrorMessage = "账号不存在或已过期";
            }
            return result;
        }

        public async Task<List<UserInfo>> GetUsersByRole(int roleID)
        {
            return await (from t in base.Client.Queryable((UserInfo t, User_RoleInfo m) => t.Id == m.User_ID && m.Role_ID == roleID)
                          orderby t.Name
                          select t).ToListAsync();
        }

        public async Task<List<UserInfo>> GetUsersByOU(int ouID)
        {
            return await (from t in base.Client.Queryable((UserInfo t, OU_UserInfo m) => t.Id == m.User_ID && m.Ou_ID == ouID)
                          orderby t.Name
                          select t).ToListAsync();
        }

        public async Task<List<UserInfo>> FindByDept(int ouID)
        {
            return (await GetAllAsync((UserInfo s) => s.Dept_ID == ((int)ouID).ToString()))?.Items.ToList();
        }

        public async Task<bool> ModifyPassword(string userName, string userPassword, string systemType = null)
        {
            bool result = false;
            UserInfo userInfo = await GetFirstAsync((UserInfo s) => s.Name == userName);
            if (userInfo != null)
            {
                userPassword = EncryptHelper.ComputeHash(userPassword, userName.ToLower());
                userInfo.Password = userPassword;
                result = await UpdateAsync(userInfo);
                if (result)
                {
                    string note = $"{base.CurrentApiUser.FullName} 修改了用户【{userName}】的登录密码";
                    await AddOperationLog("密码修改", note);
                }
            }
            return result;
        }

        public async Task<bool> ResetPassword(int userId)
        {
            bool result = false;
            UserInfo info = await GetAsync(userId);
            if (info != null)
            {
                string password = EncryptHelper.ComputeHash("12345678", info.Name.ToLower());
                info.Password = password;
                result = await UpdateAsync(info);
                if (result)
                {
                    string note = $"{base.CurrentApiUser.FullName} 重置了用户【{info.Name}】的登录密码";
                    await AddOperationLog("密码重置", note);
                }
            }
            return result;
        }

        public async Task<bool> BatchExpire(List<int> idList, bool expired)
        {
            foreach (int id in idList)
            {
                await SetExpire(id, expired);
            }
            return true;
        }

        public async Task<bool> SetExpire(int userId, bool expired)
        {
            bool result = false;
            UserInfo info = await GetAsync(userId);
            if (info != null && info.Name != "admin")
            {
                info.IsExpire = expired;
                result = await UpdateAsync(info);
                if (result)
                {
                    string note = string.Format("{0} {1}了用户【{2}】的账号", base.CurrentApiUser.FullName, expired ? "禁用" : "启用", info.Name);
                    await AddOperationLog("用户过期设置", note);
                }
            }
            return result;
        }

        public async Task<bool> CancelExpire(int userID)
        {
            bool result = false;
            UserInfo userInfo = await GetAsync(userID);
            if (userInfo.IsExpire)
            {
                userInfo.IsExpire = false;
                result = await UpdateAsync(userInfo);
            }
            return result;
        }

        public async Task<string> GetFullNameByID(int id)
        {
            return (await GetAsync(id))?.FullName;
        }

        public async Task<string> GetFullNameByName(string userName)
        {
            return (await GetFirstAsync((UserInfo s) => s.Name == userName))?.FullName;
        }

        public override async Task<bool> InsertAsync(UserInfo input)
        {
            var count = await base.CountAsync(x => x.Name.ToLower() == input.Name.ToLower());
            if (count > 0)
            {
                throw new Exception($"已存在用户名 {input.Name}");
            }

            if (string.IsNullOrWhiteSpace(input.Password))
            {
                input.Password = EncryptHelper.ComputeHash("12345678", input.Name.ToLower());
            }

            return await base.InsertAsync(input);
        }

        public override async Task<bool> UpdateAsync(UserInfo input)
        {
            var count = await base.CountAsync(x => x.Name.ToLower() == input.Name.ToLower() && x.Id != input.Id);
            if (count > 0)
            {
                throw new Exception($"已存在用户名 {input.Name}");
            }
            if (input.Password.Length < 50)
            {
                input.Password = EncryptHelper.ComputeHash(input.Password, input.Name.ToLower());
            }
            return await base.UpdateAsync(input);
        }

        public async Task<CommonResult> UpdateUser(UpdateUserDto input)
        {
            CommonResult result = new CommonResult();
            UserInfo userInfo = await base.GetAsync(input.ID);
            if (userInfo != null)
            {
                if (!string.IsNullOrEmpty(input.Gender))
                {
                    userInfo.Gender = input.Gender;
                }
                if (!string.IsNullOrEmpty(input.FullName))
                {
                    userInfo.FullName = input.FullName;
                }
                if (!string.IsNullOrEmpty(input.Nickname))
                {
                    userInfo.Nickname = input.Nickname;
                }
                if (!string.IsNullOrEmpty(input.MobilePhone))
                {
                    userInfo.MobilePhone = input.MobilePhone;
                }
                if (!string.IsNullOrEmpty(input.OfficePhone))
                {
                    userInfo.OfficePhone = input.OfficePhone;
                }
                if (!string.IsNullOrEmpty(input.Signature))
                {
                    userInfo.Signature = input.Signature;
                }
                if (!string.IsNullOrEmpty(input.Address))
                {
                    userInfo.Address = input.Address;
                }
                if (!string.IsNullOrEmpty(input.Email))
                {
                    userInfo.Email = input.Email;
                }
                if (input.Birthday.HasValue)
                {
                    userInfo.Birthday = input.Birthday.Value;
                }
                CommonResult commonResult = result;
                commonResult.Success = await base.UpdateAsync(userInfo);
            }
            else
            {
                result.ErrorMessage = "用户ID不存在";
            }
            return result;
        }
    }

}
